package com.sakiko.audiobook.album.api;

import com.sakiko.audiobook.album.config.MinioConstantProperties;
import com.sakiko.audiobook.common.result.Result;
import io.minio.*;
import io.minio.errors.MinioException;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;

@Tag(name = "上传管理接口")
@RestController
@RequestMapping("api/album")
public class FileUploadApiController {

    @Autowired
    private MinioConstantProperties minioConstantProperties;

    /**
     * 使用 Minio进行文件存储: 免费、开源 支持存储的数据在 nk ~ 5T 大小不等的数据；
     * 在最高冗余配置下，丢失 N/2 磁盘时，依然能够找回数据 ==> 使用纠删码、checksum来防止硬件错误和静默数据污染
     * 纠删码是一种恢复丢失和损坏数据的数学算法
     *
     * @param file
     * @return
     */
    @Operation(summary = "文件上传")
    @PostMapping("/fileUpload")
    public Result fileupload(MultipartFile file) {
        // 文件的路径
        String url = "";
        try {
            // Create a minioClient with the MinIO server playground, its access key and secret key.
            MinioClient minioClient =
                    MinioClient.builder()
                            .endpoint(minioConstantProperties.getEndpointUrl())
                            .credentials(minioConstantProperties.getAccessKey(), minioConstantProperties.getSecreKey())
                            .build();

            // Make 'asiatrip' bucket if not exist.
            boolean found =
                    minioClient.bucketExists(BucketExistsArgs.builder().bucket(minioConstantProperties.getBucketName()).build());
            if (!found) {
                // Make a new bucket called 'asiatrip'.
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(minioConstantProperties.getBucketName()).build());
                // 添加访问权限
                minioClient.setBucketPolicy(SetBucketPolicyArgs.builder().bucket(minioConstantProperties.getBucketName()).config(createBucketPolicyConfig(minioConstantProperties.getBucketName())).build());
            } else {
                System.out.println("Bucket '" + minioConstantProperties.getBucketName() + "' already exists.");
            }

            // Upload '/home/user/Photos/asiaphotos.zip' as object name 'asiaphotos-2015.zip' to bucket

            String originalFileName = file.getOriginalFilename();
            String fileSuffix = originalFileName.substring(originalFileName.lastIndexOf("."));
            String fileName = UUID.randomUUID().toString().replaceAll("-", "") + fileSuffix;

            minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket(minioConstantProperties.getBucketName())
                            .object(fileName)
                            .stream(file.getInputStream(), file.getSize(), -1)
                            .contentType(file.getContentType())
                            .build()
            );

            url = minioConstantProperties.getEndpointUrl() + "/" +
                    minioConstantProperties.getBucketName() + "/" + fileName;

            // 返回图片地址
            return Result.ok(url);

        } catch (MinioException e) {
            System.out.println("Error occurred: " + e);
            System.out.println("HTTP trace: " + e.httpTrace());
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        } catch (InvalidKeyException e) {
            throw new RuntimeException(e);
        }
        return Result.fail("");
    }

    // bucket 授权策略
    private String createBucketPolicyConfig(String bucketName) {
        return """
                {
                  "Statement" : [ {
                    "Action" : "s3:GetObject",
                    "Effect" : "Allow",
                    "Principal" : "*",
                    "Resource" : "arn:aws:s3:::%s/*"
                  } ],
                  "Version" : "2012-10-17"
                }
                """.formatted(bucketName);
    }

}
